package auctionatr

import org.apache.jasper.compiler.Node.ParamsAction;

/**
 * Diese Klasse ist der entsprechende Controller zur Model-class User. Alle Methoden, die in Verbindung mit einem User stehen, werden u.a. in dieser Klasse gesteuert. Dies sind vor allem die Aktivitäten, die im Bereich "mein account" durchgeführt werden.
 * 
 * @author Can Paul
 *
 */
class UserController extends BaseController {

	/**
	 * Navigationsleiste mit den Elementen "registrieren", "login", "logout", "meine auktionen", "meine gebote".
	 * 
	 */
	static navigation = [
		group: 'main',
		order:2,
		title:'meinaccount',
		action:'index',
		path: 'user',
		subItems:
		[
			[order: 1, title: 'registrieren', action: 'create', isVisible: { session.username == null }],
			[title: 'logout', action: 'logout', isVisible: { session.username != null }],
			[title: 'login', action: 'login', isVisible: { session.username == null }],
			// für Userliste: [action: 'list', isVisible: { session.admin == true }],
			[title: 'myauctions', action: 'auctionList', isVisible: { session.username != null }],
			[title: 'mybids', action: 'bidList', isVisible: { session.username != null }],
			// um sicherzustellen, dass Submenü angezeigt wird:
			[action: 'show', isVisible: { false }],
			[action: 'save', isVisible: { false }],
		]
	]


	/**
	 * <!-- TODO -->
	 */
	static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

	/**
	 * <!-- TODO -->
	 */
	def index = {
		// Erneute Zuweisung der Flash-Message ist notwendig, um mehrere Weiterleitungen nacheinander die Nachricht aufrecht zu erhalten.
		if(flash.message) {
			flash.message = flash.message;
		}

		redirect(action: "show", params: [id: session.userid])
	}

// Userliste für Admin könnte so angezeigt werden:	
//	def list = {
//		if(session.admin){
//			params.max = Math.min(params.max ? params.int('max') : 10, 100)
//			[userInstanceList: User.list(params), userInstanceTotal: User.count()]
//
//		} else
//		{
//			flash['message'] = "${message(code: 'default.adminonly.message')}"
//			redirect(controller:'portal', action:'index')
//		}
//	}

	/**
	 * Diese Seite zeigt eine Liste aller angelegten Auktionen des eingeloggten Users an. 
	 */
	def auctionList = {
		def max = (params.max ? params.int('max') : 10)
		def offset = (params.offset ? params.int('offset') : 0)
		// finde alle Auktionen von mir
		def userInstance = User.get(session?.userid)

		def auctionInstanceList = Auction.executeQuery("select id, a.name, description, finishDate, startPrice,  (SELECT max(gebot) FROM Bid WHERE auctions = a.id) as gebot FROM Auction as a WHERE a.users = ? ORDER BY a.id DESC", [userInstance], [max: max, offset: offset])
		def auctionInstanceCount = Auction.executeQuery("select id FROM Auction as a WHERE a.users = ? ORDER BY a.id DESC", [userInstance])
		
		[auctionInstanceList: auctionInstanceList, auctionInstanceTotal: auctionInstanceCount.size()]
	}

	/**
	 * Diese Seite zeigt eine Liste aller Gebote, die der eingeloggte User abgegeben hat. Die Liste zeigt die Höhe des eigenen Gebots, Abgabezeitpunkt und die zugehörige Auktion mit Beschreibung an.
	 */
	def bidList = {
		def max = (params.max ? params.int('max') : 10)
		def offset = (params.offset ? params.int('offset') : 0)
		// finde alle Auktionen von mir, die noch laufen:
		def userInstance = User.get(session?.userid)
				
		def auctionInstanceList = Bid.executeQuery("SELECT auctions.id, auctions.name, auctions.description, auctions.finishDate, max(b.gebot), (SELECT max(hbt.gebot) FROM Bid as hbt WHERE hbt.auctions = b.auctions) as highestBid FROM Bid AS b WHERE b.users = ? GROUP BY b.auctions ORDER BY b.auctions.finishDate ASC", [userInstance], [max: max, offset: offset])
		def auctionInstanceCount = Bid.executeQuery("SELECT auctions.id FROM Bid AS b WHERE b.users = ? GROUP BY b.auctions ORDER BY b.auctions.finishDate ASC", [userInstance])
		
		[auctionInstanceList: auctionInstanceList, auctionInstanceTotal: auctionInstanceCount.size()]
	}

	/**
	 * Auf dieser Seite kann ein neuer User registriert werden.
	 */
	def create = {
		// Registrierung nur möglich, wenn niemand eingeloggt
		if (!session.username){
			def userInstance = new User()
			userInstance.properties = params

			return [userInstance: userInstance]
		} else{ // falls eingeloggt:
			flash['message'] = "${message(code: 'default.alreadyloggedin.message')}"
			redirect(controller:'user', action:'index')
		}

	}

	/**
	 * Beim Klick auf "registrieren" werden die eingegebenen Daten für den neuen User abgespeichert.
	 * Dem User wird automatisch die Rolle "User" zugewiesen, d.h. er besitzt keine Administrationsrechte.
	 * Nach erfolgreicher Registrierung gelangt der User zur Loginansicht, es erscheint eine Bestätigungsbenachrichtigung, dass der User erfolgreich angelegt wurde, und der User kann sich einloggen, um zur Profilansicht zu gelangen. 
	 * Wenn ein User nicht erfolgreich registriert werden konnte, erscheinen entsprechende Fehlermeldungen und der User bleibt auf der Registrierungsseite.
	 */
	def save = {
		def userInstance = new User(params)
		def f = request.getFile('avatar') //PF: This extracts the avatar file from the HTTP upload request
		if (!f.empty) { // falls Bild hochgeladen wurde:
			def accepted = [
				'image/png',
				'image/jpeg',
				'image/gif'] //Contains the accepted filetypes
			if (!accepted.contains(f.getContentType())){
				// auch alle anderen Felder validieren:
				userInstance.validate()

				// danach manuell den Fehler für falschen Dateitypen hinzufügen:
				userInstance.errors.rejectValue("avatar","default.file.wrongType.message")

				// Create view neu rendern, danach Methode beenden
				render(view: "create", model: [userInstance: userInstance])
				return;
			}
			userInstance.avatar = f.getBytes() //Copy the bytestream into the user object
			userInstance.avatarType = f.getContentType() //Copy the filetype into the user object
		} else { // falls kein Bild hochgeladen wurde, null setzen und Vorgang fortsetzen
			userInstance.avatar = null
			userInstance.avatarType = null
		}

		//Speichern
		if (userInstance.save(flush: true)) {
			flash.message = "${message(code: 'user.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])}"
			redirect(action: "login", id: userInstance.id)
		}
		else { // falls Fehler beim Speichern
			render(view: "create", model: [userInstance: userInstance])
		}
	}

	/**
	 * Anzeige des Userprofils
	 */
	def show = {
		def userInstance = User.get(params.id)
		if (!userInstance) {
			flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
			redirect(action: "list")
		}
		else {
			[userInstance: userInstance]
		}
	}

	/**
	 * Auf dieser Seite kann der User sein Profil bearbeiten.
	 */
	def edit = {

		// nur erlaubt, wenn eigenes Profil oder Adminzugriff
		if(session?.userid?.toString() == params.id || session?.admin ==true) {
			// User ID aus URL checken
			def userInstance = User.get(params.id)
			if (!userInstance) { // falls User nicht gefunden - Fehlermeldung
				flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
				redirect(action: "list")
			}
			else { // falls User gefunden: Daten in Formular
				return [userInstance: userInstance]
			}
		} else // falls nicht eigenes Profil oder Adminaccount
		{
			flash['message'] = "${message(code: 'default.accessdenied.message')}"
			redirect(action: "show", params: [id: params.id])
		}

	}

	/**
	 * Darstellung des Profilbildes im Browser
	 */
	def avatarImage={
		def userInstance= User.get(params.id) //everything OK?

		if(!userInstance || !userInstance.avatar|| !userInstance.avatarType){
			response.sendError(404) //send 404 error (file not found)
			return;
		}
		response.setContentType(userInstance.avatarType) //PF: these 5 lines build the HTML statement
		response.setContentLength(userInstance.avatar.size())
		OutputStream out = response.getOutputStream();
		out.write(userInstance.avatar);
		out.close();

	}

	/**
	 * Userbild löschen
	 */
	def deleteAvatar={
		//PF: Delete your uploaded Avatar, taking access control procedure from the edit method
		if(session?.userid?.toString() == params.id || session?.admin == true) {
			// User ID aus URL checken
			def userInstance = User.get(params.id)
			if (!userInstance) { // falls User nicht gefunden
				flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
				redirect(action: "show", params: [id: params.id])
			}
			else { // falls User gefunden: löschen
				userInstance.avatar = null
				userInstance.avatarType = null
				flash.message = "${message(code: 'default.file.deleted.message')}"
				redirect(action: "show", params: [id: params.id])
			}
		} else // falls keine Rechte vorhanden:
		{
			flash['message'] = "${message(code: 'default.accessdenied.message')}"
			redirect(action: "show", params: [id: params.id])
		}
	}

	/**
	 * Aktualisierte Daten des Userprofils überschreiben die vorhandenen Daten.
	 */
	def update = {

		if(session?.userid?.toString() == params.id || session?.admin == true) {
			def userInstance = User.get(params.id)
			// falls kein Bild hochgeladen wurde:
			def userAvatar = userInstance.avatar
			def userAvatarType = userInstance.avatarType

			if (userInstance) {
				if (params.version) {
					def version = params.version.toLong()
					if (userInstance.version > version) {

						userInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [
							message(code: 'user.label', default: 'User')]
						as Object[], "Another user has updated this User while you were editing")
						render(view: "edit", model: [userInstance: userInstance])
						return
					}
				}

				userInstance.properties = params

				def f = request.getFile('avatar') //PF: This extracts the avatar file from the HTTP upload request

				if (!f.empty) { // falls Bild vorhanden
					def accepted = [
						'image/png',
						'image/jpeg',
						'image/gif'] //Contains the accepted filetypes
					if (!accepted.contains(f.getContentType())){
						// auch alle anderen Felder validieren:
						userInstance.validate()

						// danach manuell den Fehler für falschen Dateitypen hinzufügen:
						userInstance.errors.rejectValue("avatar","default.file.wrongType.message")

						// Create view neu rendern, danach Methode beenden
						render(view: "edit", model: [userInstance: userInstance], params: params)
						return;
					}
					userInstance.avatar = f.getBytes() //Copy the bytestream into the user object
					userInstance.avatarType = f.getContentType() //Copy the filetype into the user object

				} else { // falls kein Bild vorhanden
					userInstance.avatar = userAvatar
					userInstance.avatarType = userAvatarType
				}

				// Speichern
				if (!userInstance.hasErrors() && userInstance.save(flush: true)) {
					flash.message = "${message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), userInstance.username])}"
					redirect(action: "show", id: userInstance.id)
				} else { // falls Fehler beim Speichern
					render(view: "edit", model: [userInstance: userInstance])
					return;
				}
			}
			else {// falls keine UserInstanz gefunden
				flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
				redirect(action: "list")
			}
		} else { // falls Rechte nicht korrekt
			flash['message'] = "${message(code: 'default.accessdenied.message')}"
			redirect(action: "show", params: [id: params.id])
		}
	}	

	/**
	 * Userprofil löschen
	 */
	def delete = {
		def userInstance = User.get(params.id)
		// nur eigenes Profil oder Admin
		if(session?.userid?.toString() == params.id || session?.admin == true) {
			if (userInstance) { // falls User gefunden
				try {
					userInstance.delete(flush: true)
					// falls eigener Nutzer gelöscht, ausloggen:
					if(session?.userid?.toString() == params.id) {
						session.username = null
						session.admin=null
						session.userid=null
					}
					flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
					redirect(controller: "portal", action: "index")
				}
				catch (org.springframework.dao.DataIntegrityViolationException e) {
					flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
					redirect(action: "show", id: params.id)
				}
			}
			else { // falls User nicht gefunden
				flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
				redirect(controller: "portal", action: "index")
			}
		} else { // falls keine Rechte vorhanden
			flash['message'] = "${message(code: 'default.accessdenied.message')}"
			redirect(action: "show", params: [id: params.id])
		}
	}

	/**
	 * Login-Seite.
	 * Nach erfolgreichem Login wird der User auf sein Userprofil weitergeleitet.
	 * Beim verfehlten Login-Versuch wird eine entsprechende Fehlermeldung angezeigt und der User bleibt auf der Login-Seite.
	 */
	def login = {

		// POST Request und noch nicht eingeloggt, Login Prozessur:
		if (request.method != "GET" && session.username == null) {
			// Nutzer suchen in DB:
			def user = User.findByUsernameAndPassword(params.username,params.password.encodeAsSHA())

			// falls nutzer mit richtigen Daten in DB gefunden:
			if (user) {

				// Sessiondaten setzen
				session.username = user.username //Joe: username an die Session übergeben
				session.admin = user.admin //Joe: admin(ja/nein) an die Session übergeben
				session.userid=user.id //Joe: userId an die Session übergeben

				flash['message'] = "${message(code: 'user.login.success.message')}"

				// Max: funktioniert durch Navigationsplugin nicht richtig, wenn man über mehrere Weiterleitungen kommt
				def redirectParams = //Joe: sorgt dafür, dass man auf die ursprüngliche Seite weitergeleitet wird
						session.originalRequestParams ?
						session.originalRequestParams :
						[controller:'portal', action: 'index']
				session.originalRequestParams=null
				redirect(redirectParams)
				
//				redirect(controller: 'user', action: 'show', params : [id : session.userid])

			}
			else {
				flash['message'] = "${message(code: 'user.login.incorrect.message')}"
			}
		
		} else if (request.method == "GET" && session.username == null) { // nicht eingeloggter User
			// show view
		} else { // bereits eingeloggt
		
			redirect(controller: 'portal', action: 'index')
		}
	}

	/**
	 * Ausloggen des aktiven Users.
	 * Der Logout-Vorgang wird mit einer Benachrichtigung bestätigt, falls er erfolgreich war.
	 */
	def logout = {
		//Joe: entfernt den User aus der Session
		session.username = null
		session.admin=null
		session.userid=null
		flash.message = "${message(code: 'user.logout.success.message')}"

		redirect(controller:'portal', action:'index')
	}
	
	def createAuction = {
		redirect(controller: 'auction', action: 'create')
	}

	// Authentifizierung immer, ausser:
	def beforeInterceptor = [action:this.&auth,except:[
			'login',
			'logout',
			'create',
			'save',
		]]

}
